package com.breeze.components.redis.config;

import cn.hutool.core.util.ObjectUtil;
import com.breeze.components.core.util.json.Jackson;
import com.breeze.components.redis.config.properties.RedissonProperties;
import com.breeze.components.redis.handler.KeyPrefixHandler;
import com.breeze.components.redis.manager.PlusSpringCacheManager;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.redisson.client.codec.StringCodec;
import org.redisson.codec.CompositeCodec;
import org.redisson.codec.TypedJsonJacksonCodec;
import org.redisson.spring.starter.RedissonAutoConfigurationCustomizer;
import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.context.annotation.Bean;

/**
 * redisson配置
 *
 * @author breeze
 */
@Slf4j
@AutoConfiguration
@EnableCaching
@EnableConfigurationProperties(RedissonProperties.class)
public class RedissonConfig {

  @Resource private RedissonProperties redissonProperties;

  @Bean
  public RedissonAutoConfigurationCustomizer redissonCustomizer() {
    return config -> {
      TypedJsonJacksonCodec jsonCodec =
          new TypedJsonJacksonCodec(Object.class, Jackson.getObjectMapper());
      // 组合序列化 key 使用 String 内容使用通用 json 格式
      CompositeCodec codec = new CompositeCodec(StringCodec.INSTANCE, jsonCodec, jsonCodec);
      config
          .setThreads(redissonProperties.getThreads())
          .setNettyThreads(redissonProperties.getNettyThreads())
          // 缓存 Lua 脚本 减少网络传输(redisson 大部分的功能都是基于 Lua 脚本实现)
          .setUseScriptCache(true)
          .setCodec(codec);
      RedissonProperties.SingleServerConfig singleServerConfig =
          redissonProperties.getSingleServerConfig();
      if (ObjectUtil.isNotNull(singleServerConfig)) {
        // 使用单机模式
        config
            .useSingleServer()
            // 设置redis key前缀
            .setNameMapper(new KeyPrefixHandler(redissonProperties.getKeyPrefix()))
            .setTimeout(singleServerConfig.getTimeout())
            .setClientName(singleServerConfig.getClientName())
            .setIdleConnectionTimeout(singleServerConfig.getIdleConnectionTimeout())
            .setSubscriptionConnectionPoolSize(
                singleServerConfig.getSubscriptionConnectionPoolSize())
            .setConnectionMinimumIdleSize(singleServerConfig.getConnectionMinimumIdleSize())
            .setConnectionPoolSize(singleServerConfig.getConnectionPoolSize());
      }
      // 集群配置方式 参考下方注释
      RedissonProperties.ClusterServersConfig clusterServersConfig =
          redissonProperties.getClusterServersConfig();
      if (ObjectUtil.isNotNull(clusterServersConfig)) {
        config
            .useClusterServers()
            // 设置redis key前缀
            .setNameMapper(new KeyPrefixHandler(redissonProperties.getKeyPrefix()))
            .setTimeout(clusterServersConfig.getTimeout())
            .setClientName(clusterServersConfig.getClientName())
            .setIdleConnectionTimeout(clusterServersConfig.getIdleConnectionTimeout())
            .setSubscriptionConnectionPoolSize(
                clusterServersConfig.getSubscriptionConnectionPoolSize())
            .setMasterConnectionMinimumIdleSize(
                clusterServersConfig.getMasterConnectionMinimumIdleSize())
            .setMasterConnectionPoolSize(clusterServersConfig.getMasterConnectionPoolSize())
            .setSlaveConnectionMinimumIdleSize(
                clusterServersConfig.getSlaveConnectionMinimumIdleSize())
            .setSlaveConnectionPoolSize(clusterServersConfig.getSlaveConnectionPoolSize())
            .setReadMode(clusterServersConfig.getReadMode())
            .setSubscriptionMode(clusterServersConfig.getSubscriptionMode());
      }
      log.info("初始化 redisson 配置...");
    };
  }

  /** 自定义缓存管理器 整合spring-cache */
  @Bean
  public CacheManager cacheManager() {
    return new PlusSpringCacheManager();
  }

  /*
   * redis集群配置 yml
   *
   * --- # redis 集群配置(单机与集群只能开启一个另一个需要注释掉)
   * spring.data:
   *   redis:
   *     cluster:
   *       nodes:
   *         - 192.168.0.100:6379
   *         - 192.168.0.101:6379
   *         - 192.168.0.102:6379
   *     # 密码
   *     password:
   *     # 连接超时时间
   *     timeout: 10s
   *     # 是否开启ssl
   *     ssl.enabled: false
   *
   * redisson:
   *   # 线程池数量
   *   threads: 16
   *   # Netty线程池数量
   *   nettyThreads: 32
   *   # 集群配置
   *   clusterServersConfig:
   *     # 客户端名称
   *     clientName: ${app.id}
   *     # master最小空闲连接数
   *     masterConnectionMinimumIdleSize: 32
   *     # master连接池大小
   *     masterConnectionPoolSize: 64
   *     # slave最小空闲连接数
   *     slaveConnectionMinimumIdleSize: 32
   *     # slave连接池大小
   *     slaveConnectionPoolSize: 64
   *     # 连接空闲超时，单位：毫秒
   *     idleConnectionTimeout: 10000
   *     # 命令等待超时，单位：毫秒
   *     timeout: 3000
   *     # 发布和订阅连接池大小
   *     subscriptionConnectionPoolSize: 50
   *     # 读取模式
   *     readMode: "SLAVE"
   *     # 订阅模式
   *     subscriptionMode: "MASTER"
   */
}
